// Copyright (c) Meta Platforms, Inc. and affiliates.

#ifndef ZSTRONG_DECOMPRESS_DECODE_FRAME_HEADER_H
#define ZSTRONG_DECOMPRESS_DECODE_FRAME_HEADER_H

#include "openzl/common/vector.h"
#include "openzl/common/wire_format.h" // PublicTransformInfo, ZL_FrameHeaderInfo
#include "openzl/shared/portability.h"
#include "openzl/zl_decompress.h" // ZL_FrameInfo
#include "openzl/zl_errors.h"     // ZL_Report

ZL_BEGIN_C_DECLS

/* User-facing public symbols defined in this unit
 * and exposed in zstrong/zs2_decompress.h
 */
// ZL_Report ZL_getDecompressedSize(const void* src, size_t srcSize)
// ZL_Report ZL_getHeaderSize(const void* src, size_t srcSize)

/* Non-public symbols exposed by this unit */

typedef struct {
    PublicTransformInfo trpid;
    size_t trhStart; // Start position of this transform header
    size_t trhSize;  // Size of this transform header
    size_t nbVOs;    // Nb of VOs (effectively variable nb of inputs) to be
                     // ingested by this transform
    size_t nbRegens; // Nb of streams regenerated by this transform
    const uint32_t* regenDistances; // distance indicators to position the
                                    // streams regenerated by this transform
} DFH_NodeInfo;

DECLARE_VECTOR_TYPE(DFH_NodeInfo)

/// This structure describes the content of a valid frame header.
/// It must be initialized by DFH_init(), and is filled by
/// DFH_decodeFrameHeader().
/// At end of life, it must be destroyed by DFH_destroy().
typedef struct {
    ZL_FrameInfo* frameinfo; // Holds information about the final regenerated
                             // streams presented to the user, such as their
                             // count, types and sizes.
    size_t nbStoredStreams;  // nb of streams stored in the frame
    VECTOR(size_t) storedStreamSizes; // size of each stored stream
    size_t nbDTransforms; // nb of decoder Transforms described by the frame
    VECTOR(uint32_t)
    regenDistances;  // distance indicators to position the streams
                     // regenerated by decoder transforms
    size_t nbRegens; // nb of streams regenerated by decoder transforms
    VECTOR(DFH_NodeInfo) nodes; // info about each decoder transform
    size_t totalTHSize;     // Size of all private transform headers combined
    uint32_t formatVersion; // Format version of the frame
} DFH_Struct;

/// Init the @p dfh
void DFH_init(DFH_Struct* dfh);

/// Destroys the @p dfh and releases its resources
void DFH_destroy(DFH_Struct* dfh);

/**
 * Decode the frame header starting at @src
 * and fill @p dfh with corresponding information.
 *
 * @return : size of frame header if success, or an error code
 *
 * NOTE: Convenience wrapper around the DFH_Interface that dispatches
 * to the correct decoder.
 */
ZL_Report
DFH_decodeFrameHeader(DFH_Struct* dfh, const void* src, size_t srcSize);

/**
 * Decode the chunk header starting at @src
 * and fill @dfh with corresponding information.
 * @p dfh must have already been initialized with DFH_decodeFrameHeader()
 *
 * @return : size of chunk header if success, or an error code
 *
 * NOTE: Convenience wrapper around the DFH_Interface that dispatches
 * to the correct decoder.
 */
ZL_Report
DFH_decodeChunkHeader(DFH_Struct* dfh, const void* src, size_t srcSize);

/* @note (@cyan): I kept existing names, `content` and `compressed` checksums,
 * but maybe there are better ones possible.
 * For example, `encoded` & `decoded` .
 *
 * @note: provided @param fi is valid, these methods are always successful.
 */
int FrameInfo_hasContentChecksum(const ZL_FrameInfo* fi);

int FrameInfo_hasCompressedChecksum(const ZL_FrameInfo* fi);

/* note: returns 0 for versions <= 20 */
size_t FrameInfo_frameHeaderSize(const ZL_FrameInfo* fi);

ZL_END_C_DECLS

#endif // ZSTRONG_DECOMPRESS_DECODE_FRAME_HEADER_H
